package yang.itcode.service.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import yang.itcode.exception.BusinessException;
import yang.itcode.mapper.*;
import yang.itcode.model.pojo.*;
import yang.itcode.service.SalesOrderService;
import yang.itcode.utils.ThreadUtil;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static yang.itcode.constant.ErrorConstant.*;
import static yang.itcode.constant.OptionConstant.*;

@Service
public class SalesOrderServiceImpl implements SalesOrderService {

    @Autowired
    private SalesOrderMapper salesOrderMapper;
    @Autowired
    private SalesOrderItemMapper salesOrderItemMapper;
    @Autowired
    private InventoryDetailMapper inventoryDetailMapper;
    @Autowired
    private PurchaseOrderItemMapper purchaseOrderItemMapper;
    @Autowired
    private ProfitMapper profitMapper;

    @Override
    public boolean createSalesOrder(JSONObject form) {
        Integer userId = ThreadUtil.getCurrentId();
        String orderNo = form.getStr("orderNo");
        Integer customerId = form.getInt("customerId");
        LocalDate orderDate = form.get("orderDate", LocalDate.class);
        String note = form.getStr("note");
        JSONArray items = form.getJSONArray("items");
        BigDecimal totalAmount = form.getBigDecimal("totalAmount");
        List<JSONObject> itemList = items.toList(JSONObject.class);
        BigDecimal totalCost = BigDecimal.ZERO;
        BigDecimal grossProfit = BigDecimal.ZERO;
        // 参数校验
        if (orderNo == null || customerId == null || orderDate == null || totalAmount == null) {
            throw new BusinessException(SALES_ORDER_PARAM_EXCEPTION_CODE, SALES_ORDER_PARAM_EXCEPTION_MESSAGE);
        }
        BigDecimal calculatedTotalAmount = BigDecimal.ZERO;
        Map<Integer, BigDecimal> calculatedInventoryMap = new HashMap<>();
        for (JSONObject item : itemList) {
            Integer productId = item.getInt("productId");
            String code = item.getStr("code");
            String name = item.getStr("name");
            BigDecimal quantity = item.getBigDecimal("quantity");
            BigDecimal unitPrice = item.getBigDecimal("unitPrice");
            BigDecimal totalPrice = item.getBigDecimal("totalPrice");
            String priceMode = item.getStr("priceMode");
            if (productId == null || code == null || name == null || quantity == null || unitPrice == null || totalPrice == null || priceMode == null) {
                throw new BusinessException(SALES_ORDER_PARAM_EXCEPTION_CODE, SALES_ORDER_PARAM_EXCEPTION_MESSAGE);
            }
            calculatedTotalAmount = calculatedTotalAmount.add(totalPrice);
            if ("total".equals(priceMode)) {
                // 校验总价模式（判断总价除以数量是否等于单价，计算保留两位小数）
                BigDecimal calculatedUnitPrice = totalPrice.divide(quantity, 2, RoundingMode.HALF_UP);
                if (calculatedUnitPrice.compareTo(unitPrice) != 0) {
                    throw new BusinessException(SALES_PRICE_EXCEPTION_CODE, SALES_PRICE_EXCEPTION_MESSAGE);
                }
            } else if ("unit".equals(priceMode)) {
                // 校验单价模式（判断单价乘以数量是否等于总价，计算保留两位小数）
                BigDecimal calculatedTotalPrice = unitPrice.multiply(quantity).setScale(2, RoundingMode.HALF_UP);
                if (calculatedTotalPrice.compareTo(totalPrice) != 0) {
                    throw new BusinessException(SALES_PRICE_EXCEPTION_CODE, SALES_PRICE_EXCEPTION_MESSAGE);
                }
            } else {
                throw new BusinessException(SALES_PRICE_EXCEPTION_CODE, SALES_PRICE_EXCEPTION_MESSAGE);
            }
            // 计算每个商品的出库数量
            calculatedInventoryMap.put(productId, calculatedInventoryMap.getOrDefault(productId, BigDecimal.ZERO).add(quantity));
        }
        // 校验总金额
        if (calculatedTotalAmount.compareTo(totalAmount) != 0) {
            throw new BusinessException(SALES_PRICE_EXCEPTION_CODE, SALES_PRICE_EXCEPTION_MESSAGE);
        }
        // 校验库存是否充足
        for (Map.Entry<Integer, BigDecimal> entry : calculatedInventoryMap.entrySet()) {
            Integer productId = entry.getKey();
            BigDecimal requiredQuantity = entry.getValue();
            JSONObject condition = new JSONObject();
            condition.set("productId", productId);
            condition.set("orderBy", "create_time");
            condition.set("sortOrder", "desc");
            condition.set("status", 1);
            PageHelper.startPage(1, 1);
            List<InventoryDetail> inventoryDetails = inventoryDetailMapper.selectByCondition(condition);
            if (inventoryDetails.isEmpty() || inventoryDetails.get(0).getBalanceQuantity().compareTo(requiredQuantity) < 0) {
                throw new BusinessException(SALES_PRODUCT_INVENTORY_SHORTAGE_CODE, SALES_PRODUCT_INVENTORY_SHORTAGE_MESSAGE);
            }
            // 计算该商品的总成本
            BigDecimal totalCostForProduct = inventoryDetails.get(0).getCurrentAvgCost().multiply(requiredQuantity);
            totalCost = totalCost.add(totalCostForProduct);
        }
        // 插入销售单
        SalesOrder salesOrder = new SalesOrder();
        salesOrder.setOrderNo(orderNo);
        salesOrder.setCustomerId(customerId);
        salesOrder.setOrderDate(orderDate);
        salesOrder.setNote(note);
        salesOrder.setTotalAmount(totalAmount);
        salesOrder.setCreateUserId(userId);
        salesOrder.setUpdateUserId(userId);
        salesOrder.setTotalCost(totalCost);
        salesOrder.setGrossProfit(totalAmount.subtract(totalCost));
        salesOrderMapper.insert(salesOrder);
        JSONObject condition = new JSONObject();
        condition.set("orderNo", orderNo);
        List<SalesOrder> lastInsert = salesOrderMapper.selectByCondition(condition);
        if (lastInsert.isEmpty()) {
            return false;
        }
        salesOrder = lastInsert.get(0);
        // 插入销售明细，更新库存和利润
        for (JSONObject item : itemList) {
            Integer productId = item.getInt("productId");
            BigDecimal quantity = item.getBigDecimal("quantity");
            BigDecimal unitPrice = item.getBigDecimal("unitPrice");
            BigDecimal totalPrice = item.getBigDecimal("totalPrice");
            // 1) 查询该商品当前的库存信息
            condition = new JSONObject();
            condition.set("productId", productId);
            condition.set("orderBy", "create_time");
            condition.set("sortOrder", "desc");
            condition.set("status", 1);
            PageHelper.startPage(1, 1);
            List<InventoryDetail> inventoryDetails = inventoryDetailMapper.selectByCondition(condition);
            InventoryDetail latestInventory = inventoryDetails.get(0);
            BigDecimal unitCost = latestInventory.getCurrentAvgCost();
            BigDecimal totalCostForItem = unitCost.multiply(quantity).setScale(2, RoundingMode.HALF_UP);
            BigDecimal profit = totalPrice.subtract(totalCostForItem);

            // 2) 插入销售明细
            SalesOrderItem salesOrderItem = new SalesOrderItem();
            salesOrderItem.setOrderId(salesOrder.getId());
            salesOrderItem.setProductId(productId);
            salesOrderItem.setQuantity(quantity);
            salesOrderItem.setUnitPrice(unitPrice);
            salesOrderItem.setTotalPrice(totalPrice);
            salesOrderItem.setUnitCost(unitCost);
            salesOrderItem.setTotalCost(totalCostForItem);
            salesOrderItem.setProfit(profit);
            salesOrderItem.setCreateUserId(userId);
            salesOrderItem.setUpdateUserId(userId);
            salesOrderItemMapper.insert(salesOrderItem);

            // 3) 写入库存
            InventoryDetail newInventory = new InventoryDetail();
            newInventory.setProductId(productId);
            newInventory.setOperationType(INVENTORY_OPTION_SALES);
            newInventory.setQuantity(quantity.negate());
            newInventory.setCurrentAvgCost(latestInventory.getCurrentAvgCost());
            newInventory.setBalanceQuantity(latestInventory.getBalanceQuantity().subtract(quantity));
            newInventory.setBalanceValue(newInventory.getBalanceQuantity().multiply(newInventory.getCurrentAvgCost()).setScale(2, RoundingMode.HALF_UP));
            newInventory.setDate(orderDate);
            newInventory.setNote("销售出库，销售单号：" + orderNo);
            newInventory.setRelatedId(salesOrderItem.getOrderId());
            newInventory.setCreateUserId(userId);
            newInventory.setUpdateUserId(userId);
            inventoryDetailMapper.insert(newInventory);

            // 4) 写入利润
            Profit newProfit = new Profit();
            newProfit.setOperationType(PROFIT_OPTION_SALES);
            newProfit.setValue(profit);
            newProfit.setDate(orderDate);
            newProfit.setNote("销售盈利，销售单号：" + orderNo);
            newProfit.setRelatedId(salesOrderItem.getOrderId());
            newProfit.setCreateUserId(userId);
            newProfit.setUpdateUserId(userId);
            profitMapper.insert(newProfit);
        }
        return true;
    }

    @Override
    @Transactional
    public PageInfo<JSONObject> getSalesOrderList(Integer pageNum, Integer pageSize, JSONObject condition) {
        PageHelper.startPage(pageNum, pageSize);
        LocalDate[] dateRange = condition == null ? null : condition.get("dateRange", LocalDate[].class);
        if (dateRange != null && dateRange.length == 2) {
            condition.set("startDate", dateRange[0]);
            condition.set("endDate", dateRange[1]);
        }
        List<JSONObject> list = salesOrderMapper.selectSalesOrderView(condition == null ? new JSONObject() : condition);
        checkRed : for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getInt("canRed") != 1){
                list.get(i).set("canRed", false);
                continue;
            }
            list.get(i).set("canRed", true);
            condition = new JSONObject();
            condition.set("orderId", list.get(i).getInt("id"));
            condition.set("status", 1);
            List<SalesOrderItem> items = salesOrderItemMapper.selectByCondition(condition);
            for (SalesOrderItem item : items) {
                condition = new JSONObject();
                condition.set("productId", item.getProductId());
                condition.set("status", 1);
                condition.set("startTime", item.getCreateTime());
                List<PurchaseOrderItem> laterPurchaseItems = purchaseOrderItemMapper.selectByCondition(condition);
                if (!laterPurchaseItems.isEmpty()) {
                    list.get(i).set("canRed", false);
                    continue checkRed;
                }
            }
        }
        return new PageInfo<>(list);
    }

    @Override
    public JSONObject getSalesOrderDetail(Integer id) {
        if (id == null) {
            throw new BusinessException(SALES_ORDER_PARAM_EXCEPTION_CODE, SALES_ORDER_PARAM_EXCEPTION_MESSAGE);
        }
        JSONObject condition = new JSONObject();
        condition.set("id", id);
        condition.set("orderBy", "create_time");
        condition.set("sortOrder", "DESC");
        PageHelper.startPage(1,1);
        List<JSONObject> list = salesOrderMapper.selectSalesOrderView(condition);
        if (list.isEmpty()) {
            throw new BusinessException(SALES_ORDER_NOT_EXIST_EXCEPTION_CODE, SALES_ORDER_NOT_EXIST_EXCEPTION_MESSAGE);
        }
        JSONObject base = list.get(0);
        condition = new JSONObject();
        condition.set("orderId", id);
        List<JSONObject> items = salesOrderItemMapper.selectSalesOrderItemsView(condition);
        base.set("items", items);
        return base;
    }

    @Override
    public boolean updateSalesOrder(JSONObject obj) {
        Integer id = obj.getInt("id");
        String orderNo = obj.getStr("orderNo");
        Integer customerId = obj.getInt("customerId");
        String note = obj.getStr("note");
        if (id == null || orderNo == null || customerId == null) {
            throw new BusinessException(SALES_ORDER_PARAM_EXCEPTION_CODE, SALES_ORDER_PARAM_EXCEPTION_MESSAGE);
        }
        Integer userId = ThreadUtil.getCurrentId();
        SalesOrder salesOrder = new SalesOrder();
        salesOrder.setId(id);
        salesOrder.setOrderNo(orderNo);
        salesOrder.setCustomerId(customerId);
        salesOrder.setNote(note);
        salesOrder.setUpdateUserId(userId);
        return salesOrderMapper.update(salesOrder) == 1;
    }

    @Override
    @Transactional
    public boolean redSalesOrder(Integer id) {
        Integer userId = ThreadUtil.getCurrentId();
        // 查询要红冲的销售单
        JSONObject condition = new JSONObject();
        SalesOrder salesOrder = salesOrderMapper.selectById(id);
        if (salesOrder == null) {
            throw new BusinessException(SALES_ORDER_NOT_EXIST_EXCEPTION_CODE, SALES_ORDER_NOT_EXIST_EXCEPTION_MESSAGE);
        }
        // 查询该销售单所有商品
        condition.set("orderId", id);
        condition.set("status", 1);
        List<SalesOrderItem> items = salesOrderItemMapper.selectByCondition(condition);
        // 创建红冲销售单
        SalesOrder redSalesOrder = new SalesOrder();
        redSalesOrder.setOrderNo(salesOrder.getOrderNo() + "-R");
        redSalesOrder.setCustomerId(salesOrder.getCustomerId());
        redSalesOrder.setOrderDate(LocalDate.now());
        redSalesOrder.setNote("红冲单，原销售单ID：" + salesOrder.getId());
        redSalesOrder.setTotalAmount(salesOrder.getTotalAmount().negate());
        redSalesOrder.setCreateUserId(userId);
        redSalesOrder.setUpdateUserId(userId);
        redSalesOrder.setTotalCost(salesOrder.getTotalCost());
        redSalesOrder.setGrossProfit(salesOrder.getGrossProfit().negate());
        redSalesOrder.setRedOrder(1);
        redSalesOrder.setRedSourceId(salesOrder.getId());
        salesOrderMapper.insert(redSalesOrder);
        // 查询刚插入的红冲单
        condition = new JSONObject();
        condition.set("orderNo", redSalesOrder.getOrderNo());
        condition.set("status", 1);
        condition.set("orderBy", "create_time");
        condition.set("sortOrder", "DESC");
        PageHelper.startPage(1, 1);
        List<SalesOrder> lastInsert = salesOrderMapper.selectByCondition(condition);
        if (lastInsert.isEmpty()) {
            throw new BusinessException(SALES_ORDER_RED_EXCEPTION_CODE, SALES_ORDER_RED_EXCEPTION_MESSAGE);
        }
        redSalesOrder = lastInsert.get(0);
        // 更新原销售单为已红冲
        salesOrder.setRedSource(1);
        salesOrder.setRedOrderId(redSalesOrder.getId());
        salesOrder.setUpdateUserId(userId);
        salesOrderMapper.update(salesOrder);
        // 遍历商品，插入红冲销售单明细，更新库存和利润
        for (SalesOrderItem item : items) {
            // 1) 插入红冲销售单明细
            SalesOrderItem redItem = new SalesOrderItem();
            redItem.setOrderId(redSalesOrder.getId());
            redItem.setProductId(item.getProductId());
            redItem.setQuantity(item.getQuantity().negate());
            redItem.setUnitPrice(item.getUnitPrice());
            redItem.setTotalPrice(item.getTotalPrice().negate());
            redItem.setUnitCost(item.getUnitCost());
            redItem.setTotalCost(item.getTotalCost().negate());
            redItem.setProfit(item.getProfit().negate());
            redItem.setCreateUserId(userId);
            redItem.setUpdateUserId(userId);
            salesOrderItemMapper.insert(redItem);
            // 查询最新的库存信息
            condition = new JSONObject();
            condition.set("productId", item.getProductId());
            condition.set("orderBy", "create_time");
            condition.set("sortOrder", "desc");
            condition.set("status", 1);
            PageHelper.startPage(1, 1);
            List<InventoryDetail> inventoryDetails = inventoryDetailMapper.selectByCondition(condition);
            InventoryDetail latestInventory = inventoryDetails.get(0);
            // 2) 写入库存（红冲即为进货）
            InventoryDetail newInventory = new InventoryDetail();
            newInventory.setProductId(item.getProductId());
            newInventory.setOperationType(INVENTORY_OPTION_RED_SALES);
            newInventory.setQuantity(item.getQuantity());
            // 计算红冲后的单价、库存数量和库存金额
            BigDecimal newBalanceQuantity = latestInventory.getBalanceQuantity().subtract(item.getQuantity().negate());
            BigDecimal newBalanceValue = latestInventory.getBalanceValue().add(item.getTotalCost().negate());
            BigDecimal newAvgCost = latestInventory.getCurrentAvgCost();
            newInventory.setCurrentAvgCost(newAvgCost);
            newInventory.setBalanceQuantity(newBalanceQuantity);
            newInventory.setBalanceValue(newBalanceValue);
            newInventory.setDate(LocalDate.now());
            newInventory.setNote("销售单红冲入库，销售单id：" + salesOrder.getId() + "，红冲单id：" + redSalesOrder.getId());
            newInventory.setRelatedId(redItem.getOrderId());
            newInventory.setDate(LocalDate.now());
            newInventory.setCreateUserId(userId);
            newInventory.setUpdateUserId(userId);
            inventoryDetailMapper.insert(newInventory);
            // 3) 写入利润（红冲即为亏损）
            Profit newProfit = new Profit();
            newProfit.setOperationType(PROFIT_OPTION_RED_SALES);
            newProfit.setValue(item.getProfit().negate());
            newProfit.setDate(LocalDate.now());
            newProfit.setNote("销售单红冲亏损，销售单id：" + salesOrder.getId() + "，红冲单id：" + redSalesOrder.getId());
            newProfit.setRelatedId(redItem.getOrderId());
            newProfit.setCreateUserId(userId);
            newProfit.setUpdateUserId(userId);
            profitMapper.insert(newProfit);
        }
        return true;
    }
}
